<?php

/**
 * 拼多多对接
 * @date 20210618
 * @author chenshubo
 */
namespace App\Service\VendorClient\PddApi;

use App\Service\BaseService;
use Service\AppService\IdService;
use App\Service\TaskServer\TaskWorker;
use App\Service\Code\Normal;
use App\Model\PssModel\PddToken;

class ShopPddUserApiClient extends BaseService
{
    public $config;
    public $bid;
    public $method;
    public $client_id;
    public $client_secret;
    public $access_token;
    public $bonded_warehouse_list;
    public $extends;
    public $shop;
    public function __construct( $shop = null )
    {
        $this->config                   = config('api.pdd');
        $this->method                   = $this->config['routeMap'];
        $this->client_id                = $this->config['client_id'];
        $this->client_secret            = $this->config['client_secret'];
        $this->shop                     = $shop;
        $this->bid                      = $this->shop['bid'];
        $this->access_token             = $this->shop['token'];
        $this->extends                  = @json_decode($this->shop['extends'],true);
        $this->bonded_warehouse_list    = $this->extends['bonded_warehouse_list'];
    }
    
    /**
     * 批量获取电子面单
     * @param array $param
     */
    public function getWaybill( $orderList = [] )
    {
        if( empty($orderList) ) {
            return Normal::returnCode(Normal::FAIL,"订单数据不能为空");
        }
        
        //发件人信息
        $senderUserInfo = $this->extends['senderUserInfo'];
        
        if( isset($this->extends['wayUserID']) ) {
            $shop   = PddToken::instance()->info(['bid'=>$this->extends['wayUserID']]);
            $this->access_token = $shop['token'];
            //查询电子面单发货地址情况
            $res = $this->wayBillSearchByWayCode($this->extends['wp_code']);
            if( $res['code'] != Normal::SUC ) {
                return $res;
            }
            $addres = $res['data'];
        } else {
            $addres = $senderUserInfo['address'];
        }
        
        $sender = [
            'address'   => [
                'city'      => $addres['city'],
                'detail'    => $addres['detail'],
                'district'  => $addres['district'],
                'province'  => $addres['province'],
            ],
            'mobile'    => $senderUserInfo['mobile'],
            'name'      => $senderUserInfo['name'],
        ];
        $trade_order_info_dtos = [];
        $waybill_code_map = [];
        foreach ($orderList as $orderInfo )
        {
            $order_sn = $orderInfo['order_sn'];
            $order_info = [
                'order_channels_type'   => 'PIN_DUO_DUO',
                'trade_order_list'      => [$order_sn]
            ];
    
            $item_list = [];
            foreach ($orderInfo['item_list'] as $item ) {
                $item_list[] = [
                    'count' => $item['goods_count'],
                    'name'  => $item['goods_name']
                ];
            }
            $package_info = [
                'items'     => $item_list,
            ];
            $recipient = [
                'address'   => [
                    'city'      => $orderInfo['city'],
                    'detail'    => $orderInfo['receiver_address'],
                    'district'  => $orderInfo['town'],
                    'province'  => $orderInfo['province'],
                ],
                'mobile'    => $orderInfo['receiver_phone'],
                'name'      => $orderInfo['receiver_name'],
            ];
    
            $object_id = md5($order_sn.'-'.$this->guid());
            $waybill_code_map[$object_id] = $order_sn;
            $trade_order_info_dtos[] = [
                'object_id'             => $object_id,
                'order_info'            => $order_info,
                'package_info'          => $package_info,
                'recipient'             => $recipient,
                'template_url'          => $this->extends['template_url'],
                'user_id'               => $this->shop['mall_id'],
            ];
        }
    
        //获取面单主参数
        $wayBillInfo = [
            'need_encrypt'          => false,
            'sender'                => $sender,
            'trade_order_info_dtos' => $trade_order_info_dtos,
            'wp_code'               => $this->extends['wp_code']
        ];
        $data = [
            'param_waybill_cloud_print_apply_new_request'   => json_encode($wayBillInfo,JSON_UNESCAPED_UNICODE)
        ];
        $parameter = [
            'method'    => 'waybillget',
            'data'      => $data,
        ];
        $res =$this->execute($parameter);
        if( $res['code'] != Normal::SUC )  {
            return $res;
        }
    
        $pdd_waybill_get_response = $res['data']['pdd_waybill_get_response']['modules'];
        $order_waybill_list = [];
        foreach ($pdd_waybill_get_response as $item ) {
            $object_id = $item['object_id'];
            $order_waybill_list[$waybill_code_map[$object_id]] = [
                'waybill_print_data'    => $item['print_data'],
                'waybill_code'          => $item['waybill_code'],
                'object_id'             => $item['object_id']
            ];
        }
        return Normal::returnCode(Normal::SUC,"获取面单信息成功",$order_waybill_list);
    }
    
    /**
     * 查询面单服务订购及面单使用情况
     * @param unknown $way_code
     * @return mixed array
     */
    public function wayBillSearchByWayCode( $way_code = NULL )
    {
        $data = [
            'wp_code'   => $way_code
        ];
        $parameter = [
            'method'    => 'waybillsearch',
            'data'      => $data,
        ];
    
        $resWayCodeInfo= $this->execute($parameter);
        if( empty($resWayCodeInfo['data']['pdd_waybill_search_response']) ) {
            return Normal::returnCode(Normal::FAIL,"未查询到电子面单发货地址信息",$resWayCodeInfo);
        }
    
        $pdd_waybill_search_response = $resWayCodeInfo['data']['pdd_waybill_search_response'];
        if( empty($pdd_waybill_search_response['waybill_apply_subscription_cols']) ) {
            return Normal::returnCode(Normal::FAIL,"未查询到电子面单发货地址信息，waybill_apply_subscription_cols为空");
        }
        $waybill_apply_subscription_cols = current($pdd_waybill_search_response['waybill_apply_subscription_cols']);
        if( empty($waybill_apply_subscription_cols['branch_account_cols']) ) {
            return Normal::returnCode(Normal::FAIL,"未查询到电子面单发货地址信息，branch_account_cols为空");
        }
        $branch_account_cols = current($waybill_apply_subscription_cols['branch_account_cols']);
        if( empty($branch_account_cols['shipp_address_cols']) ) {
            return Normal::returnCode(Normal::FAIL,"未查询到电子面单发货地址信息，shipp_address_cols为空");
        }
        $shipp_address_cols = current($branch_account_cols['shipp_address_cols']);
        return Normal::returnCode(Normal::SUC,"获取发货地址成功",$shipp_address_cols);
    }
    
    /**
     * 获取guid 信息
     * @return string
     */
    public function guid()
    {
        mt_srand((double)microtime()*10000);
        $charid = strtoupper(md5(uniqid(rand(), true)));
        $hyphen = chr(45);// "-"
        $uuid = substr($charid, 0, 8).$hyphen
        .substr($charid, 8, 4).$hyphen
        .substr($charid,12, 4).$hyphen
        .substr($charid,16, 4).$hyphen
        .substr($charid,20,12);
        return $uuid;
    }
    
    /**
     * 获取订单详情
     * @param array $param
     */
    public function queryClearAnceInfoByOrderSn( $param = [] )
    {
        if( empty($param['order_sn']) ) {
            return Normal::returnCode(Normal::FAIL,"except param order_sn");
        }
        $data = [
            'order_sn' => $param['order_sn']
        ];
        $parameter = [
            'method'    => 'getClearAnceInfo',
            'data'      => $data,
        ];
    
        return $this->execute($parameter);
    }
    
    /**
     * 获取订单详情
     * @param array $param
     */
    public function queryOrderDetail( $param = [] )
    {
        if( empty($param['order_sn']) ) {
            return Normal::returnCode(Normal::FAIL,"except param order_sn");
        }
        $data = [
            'order_sn' => $param['order_sn']
        ];
        $parameter = [
            'method'    => 'getOrderInfo',
            'data'      => $data,
        ];
    
        return $this->execute($parameter);
    }
    
    /**
     * 重新获取清关材料和电子面单
     * @param array $orderLog
     * @return string[]|array[]
     */
    public function reGetPddOrderClearanceAndPrintDataInfoByOrderLog( array $orderLog )
    {
        $pddOrderInfo = @json_decode($orderLog['contents'],true);
        $order_sn = $orderLog['order_sn'];
    
        //准备更新数组
        $pullOrderLog = [];
        $pullOrderLog['md'] = time();
        //重新获取清关材料
        if( empty($pddOrderInfo['id_card_num']) || empty($pddOrderInfo['id_card_name']) || empty($pddOrderInfo['inner_transaction_id']) || substr($pddOrderInfo['inner_transaction_id'],0,2) == 'XP' )
        {
            $res = $this->queryClearAnceInfoByOrderSn(['order_sn'=>$order_sn]);
            //未获取成功清关材料
            if( ! isset($res['data']['clearance_response']) || empty($res['data']['clearance_response']) )
            {
                $pullOrderLog['response_msg']   = "未获取到清关材料信息";
                $pullOrderLog['pdd_status']     = 2;
                return $pullOrderLog;
            }
    
            $clearance_response = $res['data']['clearance_response'];
            if( empty($clearance_response['id_card_no']) )
            {
                $pullOrderLog['response_msg']   = "清关身份号获取失败";
                $pullOrderLog['pdd_status']     = 2;
                return $pullOrderLog;
            }
    
            if( empty($clearance_response['id_card_name']) )
            {
                $pullOrderLog['response_msg']   = "清关购买人真实姓名获取失败";
                $pullOrderLog['pdd_status']     = 2;
                return $pullOrderLog;
            }
    
            if( empty($clearance_response['inner_transaction_id']) )
            {
                $pullOrderLog['response_msg']   = "清关海关申报订单号获取失败";
                $pullOrderLog['pdd_status']     = 2;
                return $pullOrderLog;
            }
    
            if( empty($clearance_response['pay_no']) )
            {
                $pullOrderLog['response_msg']   = "清关支付单号获取失败";
                $pullOrderLog['pdd_status']     = 2;
                return $pullOrderLog;
            }
    
            //重新赋值清关材料信息
            $pddOrderInfo['id_card_num']           = $clearance_response['id_card_no'];
            $pddOrderInfo['id_card_name']          = $clearance_response['id_card_name'];
            $pddOrderInfo['inner_transaction_id']  = $clearance_response['inner_transaction_id'];
            $pddOrderInfo['pay_no']                = $clearance_response['pay_no'];
        }
    
        //获取电子面单
        $res = $this->getWaybill([$pddOrderInfo]);
        if( $res['code'] == Normal::SUC )
        {
            $waybill_info = $res['data'][$order_sn];
            $pddOrderInfo['waybill_info'] = [
                'print_code'    => 200,
                'print_msg'     => "获取面单成功",
                'print_data'    => $waybill_info['waybill_print_data'],
                'waybill_code'  => $waybill_info['waybill_code'],
                'wp_code'       => $waybill_info['object_id'],
            ];
            $pullOrderLog['contents']       = json_encode($pddOrderInfo,JSON_UNESCAPED_UNICODE);
            $pullOrderLog['response_msg']   = "电子面单获取成功";
            $pullOrderLog['pdd_status']     = 0;
            return $pullOrderLog;
        }
    
        //电子面单获取失败
        $errorMsg = isset($res['data']['error_response']['sub_msg']) ? $res['data']['error_response']['sub_msg'] : $res['msg'];
        $pddOrderInfo['waybill_info'] = [
            'print_code'    => 0,
            'print_msg'     => $errorMsg
        ];
        $pullOrderLog['contents']       = json_encode($pddOrderInfo,JSON_UNESCAPED_UNICODE);
        $pullOrderLog['response_msg']   = "电子面单获取失败【{$errorMsg}】";
        $pullOrderLog['pdd_status']     = 2;
        return $pullOrderLog;
    }
    
    /**
     * 获取系统acess token
     */
    public function getAccessToken( $code = null )
    {
        if( empty($code) ) {
            return Normal::returnCode(Normal::FAIL,"获取code为空");
        }
        $parameter = [
            'client_id'     => $this->config['client_id'],
            'timestamp'     =>  time(),
            'type'          => $this->config['routeMap']['getAccessToken'],
            'code'          => $code,
        ];
        ksort($parameter);
        $signData = implode("", [
            $this->config['client_secret'],
            $this->getStr($parameter),
            $this->config['client_secret'],
        ]);
        $parameter['sign'] = strtoupper(md5($signData));
        $data = [
            'method'    => 'getAccessToken',
            'data'      => $parameter,
        ];
        return $this->execute($data);
    }
    
    /**
     * 获取店铺信息
     * @param string $token
     */
    public function getShopMallInfoByAccessToken( $token = NULL )
    {
        $parameter = [
            'client_id'     => $this->config['client_id'],
            'timestamp'     =>  time(),
            'type'          => $this->config['routeMap']['getMallInfo'],
            'access_token'  => $token,
        ];
        ksort($parameter);
        $signData = implode("", [
            $this->config['client_secret'],
            $this->getStr($parameter),
            $this->config['client_secret'],
        ]);
        $parameter['sign'] = strtoupper(md5($signData));
        $data = [
            'method'    => 'getMallInfo',
            'data'      => $parameter,
        ];
        return $this->execute($data);
    }
    
    public function getStr( $param = [] )
    {
        $temp = [];
        foreach ($param as $k=>$v){
            $temp[] =$k.$v;
        }
        return implode("", $temp);
    }
    
    /**
     * @签名
     */
    public function makeSign( $param = [] )
    {
        //公共参数
        $common=[
            'client_id'     =>  $this->client_id,
            'access_token'  =>  $this->access_token,
            'timestamp'     =>  time(),
        ];
        $param=array_merge($param,$common);
        ksort($param);
        $signData=$this->client_secret;
        foreach ($param as $k=>$v){
            $signData.=$k.$v;
        }
        $signData.=$this->client_secret;
        $sign=strtoupper(md5($signData));
        $param['sign']=$sign;
        return $param;
    }
    
    /**
     * CURL请求
     * @param $params
     * @return mixed
     */
    public function execute( $param = [] )  
    {
        if( empty($param['data']) || empty($param['method']) ) {
            return Normal::returnCode(Normal::FAIL,"except param data or method");
        }
        
        $method         = $param['method'];
        if( !isset($this->method[$method]) ) {
            return Normal::returnCode(Normal::FAIL,"method {$method} not configured");
        }
        
        $data           = $param['data'];
        $data['type']   = $this->method[$method];
        if( !in_array($method,['getMallInfo','getAccessToken']) ) 
        {
            $data = $this->makeSign($data);
        }
        
        $url = $this->config['PDD_API_URL'];
        $parameter = [
            [
                'tag'       => 'pdd_'.$method,
                'uid'       => IdService::instance()->getOtherID(),
                'url'       => $url,
                'data'      => $data,
                'method'    => 'post',
                'format'    => 'x-www-form-urlencoded',
                'header'    => [],
            ],
        ];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $response   = @json_decode($resTask['response']['result'],true);
        if( isset($response['error_response']) ) {
            $error_msg = $response['error_response']['error_msg']??'';
            return Normal::returnCode(Normal::FAIL,$error_msg,$response);
        }
        return Normal::returnCode(Normal::SUC,"获取成功",$response);
    }
}